using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.Diagnostics.Management;
using Bowlus.Common;

namespace Bowlus.AppHost
{
    public class WebRole : RoleEntryPoint
    {
        private readonly AppHostManager appHostManager = new AppHostManager(new StorageAppRepository());

        public override bool OnStart()
        {
            BowlusHelper.ConfigureLog();

            RoleEnvironment.Changing += RoleEnvironment_Changing;

            appHostManager.Initialize();

            return base.OnStart();
        }

        public override void Run()
        {
            // Listen to sync request
            var nms = new NotifyModuleServer(delegate(string msg) {
                if (msg.Equals("AppHostSync"))
                {
                    // leave time for info to be flushed to Azure table
                    // this is a precautious wait. if the wait fail, we still have chance to Sync in poll cycle defined below.
                    Thread.Sleep(3000);
                    int changes = appHostManager.Sync();
                    if (changes > 0)
                    {
                        (new NotifyModuleClient()).NotifyAllInstancesInAnotherRole("FrontEndSync");
                    }
                }
            });
            nms.startNotifyService();

            // At the same time, keep Syncing but not very often.
            // The WCF messaging between FrontEnd and AppHost are not reliable.
            // This is useful, when the messages between FrontEnd and AppHost fail.
            while (true)
            {
                try
                {
                    Thread.Sleep(120000);
                    int changes = appHostManager.Sync();
                    if (changes > 0)
                    {
                        (new NotifyModuleClient()).NotifyAllInstancesInAnotherRole("FrontEndSync");
                    }
                }
                catch (Exception ex)
                {
                    Trace.TraceError(ex.Message + '\n' + ex.StackTrace);
                }
            }
        }

        static void RoleEnvironment_Changing(object sender, RoleEnvironmentChangingEventArgs e)
        {
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                e.Cancel = true;
            }
        }
    }
}
